"""
火山引擎豆包TTS 2.0语音合成模块
字节跳动出品，基于Seed-TTS大模型
官网: https://www.volcengine.com
文档: https://www.volcengine.com/docs/6561/79820
"""

import os
import time
import wave
import uuid
import json
import base64
from typing import List, Optional, Tuple
from pathlib import Path

import numpy as np
import requests
from pydub import AudioSegment

from ..core.models import LipSyncData
from ..utils.logger import get_logger
from ..utils.temp_file_manager import get_temp_file_manager


class VolcengineTTS:
    """火山引擎豆包TTS语音合成引擎"""

    def __init__(
        self,
        app_id: str,
        access_token: str,
        voice_type: str = "zh_female_shuangkuaisisi_moon_bigtts",  # 默认音色
        api_url: str = "https://openspeech.bytedance.com/api/v1/tts",
        speed_ratio: float = 1.0,  # 语速 0.5-2.0
        volume_ratio: float = 1.0,  # 音量 0.5-2.0
        pitch_ratio: float = 1.0,   # 音调 0.5-2.0
        emotion: str = "happy",     # 情感
        audio_format: str = "wav",  # 音频格式
        sample_rate: int = 24000,   # 采样率
        timeout: int = 30
    ):
        """
        初始化火山引擎TTS引擎
        
        Args:
            app_id: 火山引擎应用ID
            access_token: API访问令牌
            voice_type: 音色类型
            api_url: API接口地址
            speed_ratio: 语速比例 (0.5-2.0)
            volume_ratio: 音量比例 (0.5-2.0)
            pitch_ratio: 音调比例 (0.5-2.0)
            emotion: 情感类型
            audio_format: 音频格式 (wav/mp3/pcm)
            sample_rate: 采样率 (8000/16000/24000)
            timeout: 请求超时时间(秒)
        """
        self.app_id = app_id
        self.access_token = access_token
        self.voice_type = voice_type
        self.api_url = api_url
        self.speed_ratio = speed_ratio
        self.volume_ratio = volume_ratio
        self.pitch_ratio = pitch_ratio
        self.emotion = emotion
        self.audio_format = audio_format
        self.sample_rate = sample_rate
        self.timeout = timeout

        self.logger = get_logger()
        self.current_audio: Optional[AudioSegment] = None
        self.current_lipsync_data: List[LipSyncData] = []
        
        # 使用统一的临时文件管理器
        self.temp_manager = get_temp_file_manager()
        self.temp_dir = self.temp_manager.get_temp_dir('audio')
        
        self.logger.info(f"✓ 火山引擎豆包TTS引擎初始化完成")
        self.logger.info(f"   音色: {self.voice_type}")
        self.logger.info(f"   采样率: {self.sample_rate}Hz")

    def synthesize(self, text: str, speaker: Optional[str] = None) -> Tuple[Optional[AudioSegment], List[LipSyncData]]:
        """
        合成语音
        
        Args:
            text: 要合成的文本
            speaker: 临时指定音色（可选，覆盖默认音色）
            
        Returns:
            (音频对象, 口型同步数据列表)
        """
        try:
            self.logger.debug(f"正在使用火山引擎豆包TTS合成语音: {text[:50]}...")
            
            # 使用指定音色或默认音色
            current_voice_type = speaker if speaker else self.voice_type

            # 构建音频配置（不包含情感参数）
            audio_config = {
                "voice_type": current_voice_type,
                "encoding": self.audio_format,
                "speed_ratio": self.speed_ratio,
                "volume_ratio": self.volume_ratio,
                "pitch_ratio": self.pitch_ratio,
                "language": "zh-CN"  # 中文
            }
            
            # 只有当emotion不为空时才添加情感参数（部分音色不支持）
            if self.emotion:
                audio_config["emotion"] = self.emotion

            # 构建请求数据
            request_data = {
                "app": {
                    "appid": self.app_id,
                    "token": self.access_token,
                    "cluster": "volcano_tts"
                },
                "user": {
                    "uid": "ai_vtuber_user"
                },
                "audio": audio_config,
                "request": {
                    "reqid": str(uuid.uuid4()),
                    "text": text,
                    "text_type": "plain",
                    "operation": "query",
                    "with_frontend": 1,
                    "frontend_type": "unitTson"
                }
            }

            # 设置请求头
            headers = {
                "Content-Type": "application/json",
                "Authorization": f"Bearer;{self.access_token}"
            }

            # 发送请求
            self.logger.debug("发送API请求...")
            start_time = time.time()
            
            response = requests.post(
                self.api_url,
                json=request_data,
                headers=headers,
                timeout=self.timeout
            )

            request_time = time.time() - start_time
            self.logger.debug(f"API响应时间: {request_time:.2f}秒")

            # 检查响应状态
            if response.status_code != 200:
                error_msg = f"火山引擎TTS API请求失败: HTTP {response.status_code}"
                try:
                    error_detail = response.json()
                    error_msg += f" - {error_detail}"
                    self.logger.error(error_msg)
                    self.logger.error(f"完整错误: {error_detail}")
                except:
                    error_msg += f" - {response.text[:200]}"
                    self.logger.error(error_msg)
                return None, []

            # 解析响应
            response_data = response.json()
            
            # 检查响应格式
            if "code" in response_data and response_data["code"] != 3000:
                error_msg = response_data.get("message", "未知错误")
                self.logger.error(f"火山引擎TTS返回错误: {error_msg}")
                return None, []

            if "data" not in response_data:
                self.logger.error(f"火山引擎TTS响应格式错误: {response_data}")
                return None, []

            # 获取Base64编码的音频数据
            audio_base64 = response_data["data"]
            
            # 解码音频数据
            audio_bytes = base64.b64decode(audio_base64)
            
            # 保存音频到项目临时目录
            file_ext = "wav" if self.audio_format == "wav" else self.audio_format
            temp_filename = f"volcengine_tts_{uuid.uuid4().hex[:8]}.{file_ext}"
            temp_file_path = self.temp_dir / temp_filename
            
            # 跟踪临时文件
            self.temp_manager.track_file(temp_file_path)
            
            # 写入音频数据
            with open(temp_file_path, 'wb') as f:
                f.write(audio_bytes)

            # 加载音频
            if self.audio_format == "wav":
                audio = AudioSegment.from_wav(str(temp_file_path))
            elif self.audio_format == "mp3":
                audio = AudioSegment.from_mp3(str(temp_file_path))
            else:
                audio = AudioSegment.from_file(str(temp_file_path))
            
            self.current_audio = audio

            # 提取口型同步数据（使用60fps以匹配渲染）
            if self.audio_format == "wav":
                lipsync_data = self._extract_lipsync_data(str(temp_file_path), fps=60)
            else:
                # 对于非WAV格式，转换为WAV后提取
                wav_temp_path = self.temp_dir / f"volcengine_tts_{uuid.uuid4().hex[:8]}.wav"
                audio.export(str(wav_temp_path), format='wav')
                self.temp_manager.track_file(wav_temp_path)
                lipsync_data = self._extract_lipsync_data(str(wav_temp_path), fps=60)
                self.temp_manager.cleanup_file(wav_temp_path)
            
            self.current_lipsync_data = lipsync_data

            # 删除临时文件
            try:
                self.temp_manager.cleanup_file(temp_file_path)
            except Exception as e:
                self.logger.warning(f"清理临时文件失败: {e}")

            self.logger.info(
                f"✓ 火山引擎豆包TTS语音合成成功, "
                f"时长: {len(audio)/1000:.2f}秒, "
                f"口型帧数: {len(lipsync_data)}"
            )

            return audio, lipsync_data

        except requests.exceptions.Timeout:
            self.logger.error(f"火山引擎TTS API请求超时 (>{self.timeout}秒)")
            return None, []
        except requests.exceptions.RequestException as e:
            self.logger.error(f"火山引擎TTS API请求异常: {e}")
            return None, []
        except Exception as e:
            self.logger.error(f"火山引擎豆包TTS语音合成异常: {e}")
            import traceback
            self.logger.error(traceback.format_exc())
            return None, []

    def _extract_lipsync_data(self, audio_file: str, fps: int = 60) -> List[LipSyncData]:
        """
        从音频文件提取口型同步数据
        
        Args:
            audio_file: 音频文件路径
            fps: 帧率（默认60fps，匹配渲染帧率）
            
        Returns:
            口型同步数据列表
        """
        try:
            # 打开WAV文件
            with wave.open(audio_file, 'rb') as wav_file:
                # 获取音频参数
                sample_rate = wav_file.getframerate()
                n_frames = wav_file.getnframes()
                audio_data = wav_file.readframes(n_frames)
                
                # 转换为numpy数组
                audio_array = np.frombuffer(audio_data, dtype=np.int16)
                
                # 计算每帧的时间间隔
                frame_interval = 1.0 / fps
                samples_per_frame = int(sample_rate * frame_interval)
                
                lipsync_data = []
                
                # 按帧分析音频
                for i in range(0, len(audio_array), samples_per_frame):
                    frame_data = audio_array[i:i + samples_per_frame]
                    
                    if len(frame_data) == 0:
                        break
                    
                    # 计算RMS音量
                    rms = np.sqrt(np.mean(frame_data.astype(np.float32) ** 2))
                    max_amplitude = 32768.0  # 16-bit音频最大值
                    volume = min(rms / max_amplitude, 1.0)
                    
                    # 将音量映射到嘴巴张开度
                    # 豆包TTS音质极佳，使用优化的非线性映射
                    if volume > 0.01:  # 过滤噪音
                        # 幂函数映射：增强低音量可见度
                        mouth_open = min(np.power(volume * 3.0, 0.6), 1.0)
                    else:
                        mouth_open = 0.0
                    
                    # 添加口型数据
                    timestamp = i / sample_rate
                    lipsync_data.append(
                        LipSyncData(
                            timestamp=timestamp,
                            volume=volume,
                            mouth_open=mouth_open
                        )
                    )
                
                self.logger.debug(f"提取了 {len(lipsync_data)} 帧口型数据 (fps={fps})")
                return lipsync_data
                
        except Exception as e:
            self.logger.error(f"提取口型数据失败: {e}")
            return []

    def set_voice(self, voice_type: str):
        """
        切换音色
        
        Args:
            voice_type: 音色类型
        """
        self.voice_type = voice_type
        self.logger.info(f"已切换音色: {voice_type}")

    def set_emotion(self, emotion: str):
        """
        设置情感
        
        Args:
            emotion: 情感类型
        """
        self.emotion = emotion
        self.logger.debug(f"已设置情感: {emotion}")

    def set_speed(self, speed_ratio: float):
        """
        设置语速
        
        Args:
            speed_ratio: 语速比例 (0.5-2.0)
        """
        self.speed_ratio = max(0.5, min(2.0, speed_ratio))
        self.logger.debug(f"已设置语速: {self.speed_ratio}")

    def test_connection(self) -> bool:
        """
        测试API连接
        
        Returns:
            连接是否成功
        """
        try:
            self.logger.info("正在测试火山引擎豆包TTS API连接...")
            
            # 使用简短文本测试
            audio, lipsync_data = self.synthesize("你好")
            
            if audio is not None:
                self.logger.info("✓ 火山引擎豆包TTS API连接测试成功!")
                self.logger.info(f"   测试音频时长: {len(audio)/1000:.2f}秒")
                return True
            else:
                self.logger.error("✗ 火山引擎豆包TTS API连接测试失败")
                return False
                
        except Exception as e:
            self.logger.error(f"火山引擎豆包TTS API连接测试异常: {e}")
            return False

    def get_audio_duration(self, audio: Optional[AudioSegment] = None) -> float:
        """
        获取音频时长(秒)
        
        Args:
            audio: 音频对象
            
        Returns:
            音频时长(秒)
        """
        if audio is None:
            audio = self.current_audio

        if audio is None:
            return 0.0

        return len(audio) / 1000.0

    def cleanup_temp_files(self):
        """清理临时文件"""
        try:
            self.temp_manager.cleanup_all()
            self.logger.info("✓ 火山引擎豆包TTS临时文件已清理")
        except Exception as e:
            self.logger.warning(f"清理临时文件失败: {e}")


# 火山引擎豆包TTS预设音色列表
VOLCENGINE_VOICES = {
    # 中文女声
    "zh_female_shuangkuaisisi_moon_bigtts": "双快思思 - 甜美少女音（推荐）",
    "zh_female_wanwanxiaohe": "婉婉小荷 - 温柔知性",
    "zh_female_xinxinqingqing": "欣欣青青 - 清新活泼",
    "zh_female_huanbaobao": "欢宝宝 - 可爱萝莉",
    "BV700_V2_streaming": "女声主播 - 专业播报",
    "BV051_streaming": "女声助手 - 亲切温和",
    
    # 中文男声
    "zh_male_aojiaobozai_moon_bigtts": "傲娇boy - 阳光少年",
    "zh_male_zhuomoqunshushu": "卓墨群叔叔 - 成熟稳重",
    "BV406_streaming": "男声主播 - 浑厚有力",
    "BV158_streaming": "男声助手 - 专业干练",
    
    # 童声
    "BV113_streaming": "童声 - 活泼可爱",
    
    # 英文
    "en_female_bella": "Bella - 女性英文",
    "en_male_adam": "Adam - 男性英文",
}

# 情感类型（豆包TTS支持）
VOLCENGINE_EMOTIONS = [
    "happy",      # 开心
    "sad",        # 悲伤
    "angry",      # 生气
    "fear",       # 恐惧
    "surprise",   # 惊讶
    "neutral",    # 中性
]
